﻿using System;
using System.Collections.ObjectModel;


namespace advadev.CanOpen
{

    /// <summary>
    /// Represents a layer setting services switch state global transfer
    /// </summary>
    public class LayerSettingServicesSwitchStateGlobalTransfer : ITransfer
    {

        /// <summary>for internal use</summary>
        private bool _isMasterTransfer;
        /// <summary>for internal use</summary>
        private bool _isTransferCompleteAfterSending;
        /// <summary>for internal use</summary>
        private CanOpenMessage _receivedCanOpenMessage;
        /// <summary>for internal use</summary>
        private LayerSettingServicesSwitchStateGlobalMessageReceivedEventHandler _layerSettingServicesSwitchStateGlobalMessageReceivedEventHandler;
        /// <summary>for internal use</summary>
        private Collection<CanOpenMessage> _pendingSendMessages = new Collection<CanOpenMessage>();
        /// <summary>for internal use</summary>
        private ReadOnlyCollection<CanOpenMessage> _pendingSendMessagesReference;
        /// <summary>
        /// Default master COB-ID
        /// </summary>
        static public readonly UInt16 DefaultMasterCobId = 0x7E5;


        /// <summary>
        /// Initializes a new instance of the
        /// LayerSettingServicesSwitchStateGlobalTransfer class by the given
        /// parameter
        /// </summary>
        /// <param name="receivedCanOpenMessage">
        /// Received can open message
        /// </param>
        /// <param name="layerSettingServicesSwitchStateGlobalMessageReceivedEventHandler">
        /// Layer setting services switch state global message received event
        /// handler (or null)
        /// </param>
        private LayerSettingServicesSwitchStateGlobalTransfer(CanOpenMessage receivedCanOpenMessage, LayerSettingServicesSwitchStateGlobalMessageReceivedEventHandler layerSettingServicesSwitchStateGlobalMessageReceivedEventHandler)
        {
            _isMasterTransfer = false;
            _receivedCanOpenMessage = receivedCanOpenMessage;
            _layerSettingServicesSwitchStateGlobalMessageReceivedEventHandler = layerSettingServicesSwitchStateGlobalMessageReceivedEventHandler;
        }

        /// <summary>
        /// Initializes a new instance of the
        /// LayerSettingServicesSwitchStateGlobalTransfer class by the given
        /// parameter
        /// </summary>
        /// <param name="layerSettingServicesState">
        /// Layer setting services state to switch to
        /// </param>
        public LayerSettingServicesSwitchStateGlobalTransfer(LayerSettingServicesState layerSettingServicesState)
            : this(layerSettingServicesState, DefaultMasterCobId)
        {
        }

        /// <summary>
        /// Initializes a new instance of the
        /// LayerSettingServicesSwitchStateGlobalTransfer class by the given
        /// parameter
        /// </summary>
        /// <param name="layerSettingServicesState">
        /// Layer setting services state to switch to
        /// </param>
        /// <param name="masterCobId">
        /// Master COB-ID
        /// </param>
        public LayerSettingServicesSwitchStateGlobalTransfer(LayerSettingServicesState layerSettingServicesState, UInt16 masterCobId)
        {
            _isMasterTransfer = true;
            MasterCobId = masterCobId;
            LayerSettingServicesState = layerSettingServicesState;
        }


        /// <summary>
        /// Gets or sets the layer setting services state
        /// </summary>
        private LayerSettingServicesState LayerSettingServicesState
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the master COB-ID
        /// </summary>
        private UInt16 MasterCobId
        {
            get;
            set;
        }


        /// <summary>
        /// Checks if the given received can open message is a layer setting
        /// services switch state global transfer request and if so it returns
        /// as out parameter a matching layer setting services switch state
        /// global transfer instance
        /// </summary>
        /// <param name="receivedCanOpenMessage">
        /// Received can open message
        /// </param>
        /// <param name="layerSettingServicesSwitchStateGlobalTransfer">
        /// A matching layer setting services switch state global transfer
        /// instance
        /// </param>
        /// <param name="layerSettingServicesSwitchStateGlobalMessageReceivedEventHandler">
        /// Layer setting services switch state global message received event
        /// handler (or null)
        /// </param>
        /// <returns>
        /// True if the received can open message is a layer setting services
        /// switch state global transfer request, false otherwise
        /// </returns>
        static public bool IsLayerSettingServicesSwitchStateGlobalTransfer(CanOpenMessage receivedCanOpenMessage, out LayerSettingServicesSwitchStateGlobalTransfer layerSettingServicesSwitchStateGlobalTransfer, LayerSettingServicesSwitchStateGlobalMessageReceivedEventHandler layerSettingServicesSwitchStateGlobalMessageReceivedEventHandler)
        {
            return IsLayerSettingServicesSwitchStateGlobalTransfer(receivedCanOpenMessage, out layerSettingServicesSwitchStateGlobalTransfer, DefaultMasterCobId, layerSettingServicesSwitchStateGlobalMessageReceivedEventHandler);
        }

        /// <summary>
        /// Checks if the given received can open message is a layer setting
        /// services switch state global transfer request and if so it returns
        /// as out parameter a matching layer setting services switch state
        /// global transfer instance
        /// </summary>
        /// <param name="receivedCanOpenMessage">
        /// Received can open message
        /// </param>
        /// <param name="layerSettingServicesSwitchStateGlobalTransfer">
        /// A matching layer setting services switch state global transfer
        /// instance
        /// </param>
        /// <param name="masterCobId">
        /// Master COB-ID
        /// </param>
        /// <param name="layerSettingServicesSwitchStateGlobalMessageReceivedEventHandler">
        /// Layer setting services switch state global message received event
        /// handler (or null)
        /// </param>
        /// <returns>
        /// True if the received can open message is a layer setting services
        /// switch state global transfer request, false otherwise
        /// </returns>
        static public bool IsLayerSettingServicesSwitchStateGlobalTransfer(CanOpenMessage receivedCanOpenMessage, out LayerSettingServicesSwitchStateGlobalTransfer layerSettingServicesSwitchStateGlobalTransfer, UInt16 masterCobId, LayerSettingServicesSwitchStateGlobalMessageReceivedEventHandler layerSettingServicesSwitchStateGlobalMessageReceivedEventHandler)
        {
            // check parameter
            if (receivedCanOpenMessage == null)
            {
                layerSettingServicesSwitchStateGlobalTransfer = null;
                return false;
            }

            // check COB-ID
            if (receivedCanOpenMessage.CanId != masterCobId)
            {
                layerSettingServicesSwitchStateGlobalTransfer = null;
                return false;
            }

            // check command specifier
            if (receivedCanOpenMessage.Byte0 != (byte)0x04)
            {
                layerSettingServicesSwitchStateGlobalTransfer = null;
                return false;
            }

            // create transfer instance
            layerSettingServicesSwitchStateGlobalTransfer = new LayerSettingServicesSwitchStateGlobalTransfer(receivedCanOpenMessage, layerSettingServicesSwitchStateGlobalMessageReceivedEventHandler);
            return true;
        }

        /// <summary>
        /// Starts the master transfer
        /// </summary>
        private void startMasterTransfer()
        {
            UInt16 canId = MasterCobId;
            byte byte0 = 0x04;
            byte byte1 = (byte)LayerSettingServicesState;
            _pendingSendMessages.Add(new CanOpenMessage(canId, byte0, byte1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 8));
            _isTransferCompleteAfterSending = true;
        }

        /// <summary>
        /// Starts the slave transfer
        /// </summary>
        private void startSlaveTransfer()
        {
            // process data
            if (_layerSettingServicesSwitchStateGlobalMessageReceivedEventHandler != null)
            {
                LayerSettingServicesState layerSettingServicesState = LayerSettingServicesState.Unkown;
                if (_receivedCanOpenMessage.Byte1 == (byte)LayerSettingServicesState.WaitingState)
                {
                    layerSettingServicesState = LayerSettingServicesState.WaitingState;
                }
                else if (_receivedCanOpenMessage.Byte1 == (byte)LayerSettingServicesState.ConfigurationState)
                {
                    layerSettingServicesState = LayerSettingServicesState.ConfigurationState;
                }
                _layerSettingServicesSwitchStateGlobalMessageReceivedEventHandler(this, new LayerSettingServicesSwitchStateGlobalMessageReceivedEventArgs(layerSettingServicesState));
            }

            // end transfer
            TransferComplete = true;
        }


        #region ITransfer implementation
        /// <summary>
        /// Gets a flag indicating whether the transfer is complete (after
        /// sending the pending send messages)
        /// </summary>
        public bool TransferComplete
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the abort code (null for successful transfers)
        /// </summary>
        public CanOpenAbortCode AbortCode
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the pending send messages
        /// </summary>
        public ReadOnlyCollection<CanOpenMessage> PendingSendMessages
        {
            get
            {
                if (_pendingSendMessagesReference == null)
                {
                    _pendingSendMessagesReference = new ReadOnlyCollection<CanOpenMessage>(_pendingSendMessages);
                }
                return _pendingSendMessagesReference;
            }
        }


        /// <summary>
        /// Starts the transfer
        /// </summary>
        public void Start()
        {
            if (_isMasterTransfer)
            {
                startMasterTransfer();
            }
            else
            {
                startSlaveTransfer();
            }
        }

        /// <summary>
        /// Times out the transfer
        /// </summary>
        public void TimeOut()
        {
            AbortCode = new CanOpenAbortCode(0x00, 0x00, 0x04, 0x05);
        }

        /// <summary>
        /// Finalizes the transfer
        /// </summary>
        public void FinalizeTransfer()
        {
        }

        /// <summary>
        /// Continues the transfer after sending messages
        /// </summary>
        public void ContinueAfterSendingMessages()
        {
            _pendingSendMessages.Clear();
            if (_isTransferCompleteAfterSending)
            {
                TransferComplete = true;
            }
        }

        /// <summary>
        /// Processes the received message
        /// </summary>
        /// <param name="receivedCanOpenMessage">
        /// Received can open message
        /// </param>
        /// <returns>
        /// True, if the given can open message was related to this transfer,
        /// false otherwise
        /// </returns>
        public bool ProcessReceivedMessage(CanOpenMessage receivedCanOpenMessage)
        {
            return false;
        }
        #endregion ITransfer implementation

    }

}
